/**
 * echarts图表类：力导向图
 *
 * @author pissang (https://github.com/pissang/)
 *
 */


'use strict';
var ChartBase = require('./base');
var Graph = require('../data/Graph');
var ForceLayout = require('../layout/Force');
// 图形依赖
var LineShape = require('zrender/shape/Line');
var BezierCurveShape = require('zrender/shape/BezierCurve');
var ImageShape = require('zrender/shape/Image');
var IconShape = require('../util/shape/Icon');
var ecConfig = require('../config');
// 力导向布局图默认参数
ecConfig.force = {
    zlevel: 1,
    // 一级层叠
    z: 2,
    // 二级层叠
    // 布局中心
    center: [
        '50%',
        '50%'
    ],
    // 布局大小
    size: '100%',
    // 防止节点和节点，节点和边之间的重叠
    preventOverlap: false,
    // 布局冷却因子，值越小结束时间越短，值越大时间越长但是结果也越收敛
    coolDown: 0.99,
    // 数据映射到圆的半径的最小值和最大值
    minRadius: 10,
    maxRadius: 20,
    // 是否根据屏幕比例拉伸
    ratioScaling: false,
    // 在 500+ 顶点的图上建议设置 large 为 true, 会使用 Barnes-Hut simulation
    // 同时开启 useWorker 并且把 steps 值调大
    // 关于Barnes-Hut simulation: http://en.wikipedia.org/wiki/Barnes–Hut_simulation
    large: false,
    // 是否在浏览器支持 worker 的时候使用 web worker
    useWorker: false,
    // 每一帧 force 迭代的次数，仅在启用webworker的情况下有用
    steps: 1,
    // 布局缩放因子，并不完全精确, 效果跟布局大小类似
    scaling: 1,
    // 向心力因子，越大向心力越大（ 所有顶点会往 center 的位置收拢 )
    gravity: 1,
    symbol: 'circle',
    // symbolSize 为 0 的话使用映射到minRadius-maxRadius后的值
    symbolSize: 0,
    linkSymbol: null,
    linkSymbolSize: [
        10,
        15
    ],
    draggable: true,
    clickable: true,
    roam: false,
    // 分类里如果有样式会覆盖节点默认样式
    // categories: [{
    // itemStyle
    // symbol
    // symbolSize
    // name
    // }],
    itemStyle: {
        normal: {
            // color: 各异,
            label: {
                show: false,
                position: 'inside'    // textStyle: null      // 默认使用全局文本样式，详见TEXTSTYLE
            },
            nodeStyle: {
                brushType: 'both',
                borderColor: '#5182ab',
                borderWidth: 1
            },
            linkStyle: {
                color: '#5182ab',
                width: 1,
                type: 'line'
            }
        },
        emphasis: {
            // color: 各异,
            label: {
                show: false    // textStyle: null      // 默认使用全局文本样式，详见TEXTSTYLE
            },
            nodeStyle: {},
            linkStyle: { opacity: 0 }
        }
    }    // nodes: [{
         //     name: 'xxx',
         //     value: 1,
         //     itemStyle: {},
         //     initial: [0, 0],
         //     fixX: false,
         //     fixY: false,
         //     ignore: false,
         //     symbol: 'circle',
         //     symbolSize: 0
         // }]
         // links: [{
         //      source: 1,
         //      target: 2,
         //      weight: 1,
         //      itemStyle: {}
         // }, {
         //      source: 'xxx',
         //      target: 'ooo'
         // }]
};
var ecData = require('../util/ecData');
var zrUtil = require('zrender/tool/util');
var zrConfig = require('zrender/config');
var vec2 = require('zrender/tool/vector');
/**
     * 构造函数
     * @param {Object} messageCenter echart消息中心
     * @param {ZRender} zr zrender实例
     * @param {Object} series 数据
     * @param {Object} component 组件
     */
function Force(ecTheme, messageCenter, zr, option, myChart) {
    var self = this;
    // 图表基类
    ChartBase.call(this, ecTheme, messageCenter, zr, option, myChart);
    // 保存节点的位置，改变数据时能够有更好的动画效果
    this.__nodePositionMap = {};
    this._graph = new Graph(true);
    this._layout = new ForceLayout();
    this._layout.onupdate = function () {
        self._step();
    };
    this._steps = 1;
    // 关闭可拖拽属性
    this.ondragstart = function () {
        ondragstart.apply(self, arguments);
    };
    this.ondragend = function () {
        ondragend.apply(self, arguments);
    };
    this.ondrop = function () {
    };
    this.shapeHandler.ondragstart = function () {
        self.isDragstart = true;
    };
    this.onmousemove = function () {
        onmousemove.apply(self, arguments);
    };
    this.refresh(option);
}
/**
     * 绘制图形
     */
Force.prototype = {
    constructor: Force,
    type: ecConfig.CHART_TYPE_FORCE,
    _init: function () {
        this.selectedMap = {};
        var legend = this.component.legend;
        var series = this.series;
        var serieName;
        this.clear();
        for (var i = 0, l = series.length; i < l; i++) {
            var serie = series[i];
            if (serie.type === ecConfig.CHART_TYPE_FORCE) {
                series[i] = this.reformOption(series[i]);
                serieName = series[i].name || '';
                // 系列图例开关
                this.selectedMap[serieName] = legend ? legend.isSelected(serieName) : true;
                if (!this.selectedMap[serieName]) {
                    continue;
                }
                this.buildMark(i);
                // TODO 多个 force 
                this._initSerie(serie, i);
                break;
            }
        }
        this.animationEffect();
    },
    _getNodeCategory: function (serie, node) {
        return serie.categories && serie.categories[node.category || 0];
    },
    _getNodeQueryTarget: function (serie, node, type) {
        type = type || 'normal';
        var category = this._getNodeCategory(serie, node) || {};
        return [
            // Node
            node.itemStyle && node.itemStyle[type],
            // Category
            category && category.itemStyle && category.itemStyle[type],
            // Serie
            serie.itemStyle[type].nodeStyle
        ];
    },
    _getEdgeQueryTarget: function (serie, edge, type) {
        type = type || 'normal';
        return [
            edge.itemStyle && edge.itemStyle[type],
            serie.itemStyle[type].linkStyle
        ];
    },
    _initSerie: function (serie, serieIdx) {
        this._temperature = 1;
        // matrix 表示边
        if (serie.matrix) {
            this._graph = this._getSerieGraphFromDataMatrix(serie);
        }    // links 表示边
        else if (serie.links) {
            this._graph = this._getSerieGraphFromNodeLinks(serie);
        }
        this._buildLinkShapes(serie, serieIdx);
        this._buildNodeShapes(serie, serieIdx);
        var panable = serie.roam === true || serie.roam === 'move';
        var zoomable = serie.roam === true || serie.roam === 'scale';
        // Enable pan and zooom
        this.zr.modLayer(this.getZlevelBase(), {
            panable: panable,
            zoomable: zoomable
        });
        if (this.query('markPoint.effect.show') || this.query('markLine.effect.show')) {
            this.zr.modLayer(ecConfig.EFFECT_ZLEVEL, {
                panable: panable,
                zoomable: zoomable
            });
        }
        this._initLayout(serie);
        this._step();
    },
    _getSerieGraphFromDataMatrix: function (serie) {
        var nodesData = [];
        var count = 0;
        var matrix = [];
        // 复制一份新的matrix
        for (var i = 0; i < serie.matrix.length; i++) {
            matrix[i] = serie.matrix[i].slice();
        }
        var data = serie.data || serie.nodes;
        for (var i = 0; i < data.length; i++) {
            var node = {};
            var group = data[i];
            for (var key in group) {
                // name改为id
                if (key === 'name') {
                    node['id'] = group['name'];
                } else {
                    node[key] = group[key];
                }
            }
            // legends 选择优先级 category -> group
            var category = this._getNodeCategory(serie, group);
            var name = category ? category.name : group.name;
            this.selectedMap[name] = this.isSelected(name);
            if (this.selectedMap[name]) {
                nodesData.push(node);
                count++;
            } else {
                // 过滤legend未选中的数据
                matrix.splice(count, 1);
                for (var j = 0; j < matrix.length; j++) {
                    matrix[j].splice(count, 1);
                }
            }
        }
        var graph = Graph.fromMatrix(nodesData, matrix, true);
        // Prepare layout parameters
        graph.eachNode(function (n, idx) {
            n.layout = {
                size: n.data.value,
                mass: 0
            };
            n.rawIndex = idx;
        });
        graph.eachEdge(function (e) {
            e.layout = { weight: e.data.weight };
        });
        return graph;
    },
    _getSerieGraphFromNodeLinks: function (serie) {
        var graph = new Graph(true);
        var nodes = serie.data || serie.nodes;
        for (var i = 0, len = nodes.length; i < len; i++) {
            var n = nodes[i];
            if (!n || n.ignore) {
                continue;
            }
            // legends 选择优先级 category -> group
            var category = this._getNodeCategory(serie, n);
            var name = category ? category.name : n.name;
            this.selectedMap[name] = this.isSelected(name);
            if (this.selectedMap[name]) {
                var node = graph.addNode(n.name, n);
                node.rawIndex = i;
            }
        }
        for (var i = 0, len = serie.links.length; i < len; i++) {
            var e = serie.links[i];
            var n1 = e.source;
            var n2 = e.target;
            if (typeof n1 === 'number') {
                n1 = nodes[n1];
                if (n1) {
                    n1 = n1.name;
                }
            }
            if (typeof n2 === 'number') {
                n2 = nodes[n2];
                if (n2) {
                    n2 = n2.name;
                }
            }
            var edge = graph.addEdge(n1, n2, e);
            if (edge) {
                edge.rawIndex = i;
            }
        }
        graph.eachNode(function (n) {
            var value = n.data.value;
            if (value == null) {
                // value 是 null 或者 undefined
                value = 0;
                // 默认使用所有边值的和作为节点的大小, 不修改 data 里的数值
                for (var i = 0; i < n.edges.length; i++) {
                    value += n.edges[i].data.weight || 0;
                }
            }
            n.layout = {
                size: value,
                mass: 0
            };
        });
        graph.eachEdge(function (e) {
            e.layout = {
                // 默认 weight 为1
                weight: e.data.weight == null ? 1 : e.data.weight
            };
        });
        return graph;
    },
    _initLayout: function (serie) {
        var graph = this._graph;
        var len = graph.nodes.length;
        var minRadius = this.query(serie, 'minRadius');
        var maxRadius = this.query(serie, 'maxRadius');
        this._steps = serie.steps || 1;
        var layout = this._layout;
        layout.center = this.parseCenter(this.zr, serie.center);
        layout.width = this.parsePercent(serie.size, this.zr.getWidth());
        layout.height = this.parsePercent(serie.size, this.zr.getHeight());
        layout.large = serie.large;
        layout.scaling = serie.scaling;
        layout.ratioScaling = serie.ratioScaling;
        layout.gravity = serie.gravity;
        layout.temperature = 1;
        layout.coolDown = serie.coolDown;
        layout.preventNodeEdgeOverlap = serie.preventOverlap;
        layout.preventNodeOverlap = serie.preventOverlap;
        // 将值映射到minRadius-maxRadius的范围上
        var min = Infinity;
        var max = -Infinity;
        for (var i = 0; i < len; i++) {
            var gNode = graph.nodes[i];
            max = Math.max(gNode.layout.size, max);
            min = Math.min(gNode.layout.size, min);
        }
        var divider = max - min;
        for (var i = 0; i < len; i++) {
            var gNode = graph.nodes[i];
            if (divider > 0) {
                gNode.layout.size = (gNode.layout.size - min) * (maxRadius - minRadius) / divider + minRadius;
                // 节点质量是归一的
                gNode.layout.mass = gNode.layout.size / maxRadius;
            } else {
                gNode.layout.size = (maxRadius - minRadius) / 2;
                gNode.layout.mass = 0.5;
            }
        }
        for (var i = 0; i < len; i++) {
            // var initPos;
            var gNode = graph.nodes[i];
            if (typeof this.__nodePositionMap[gNode.id] !== 'undefined') {
                gNode.layout.position = vec2.create();
                vec2.copy(gNode.layout.position, this.__nodePositionMap[gNode.id]);
            } else if (typeof gNode.data.initial !== 'undefined') {
                gNode.layout.position = vec2.create();
                vec2.copy(gNode.layout.position, gNode.data.initial);
            } else {
                var center = this._layout.center;
                var size = Math.min(this._layout.width, this._layout.height);
                gNode.layout.position = _randomInSquare(center[0], center[1], size * 0.8);
            }
            var style = gNode.shape.style;
            var radius = gNode.layout.size;
            style.width = style.width || radius * 2;
            style.height = style.height || radius * 2;
            style.x = -style.width / 2;
            style.y = -style.height / 2;
            vec2.copy(gNode.shape.position, gNode.layout.position);
        }
        // 边
        len = graph.edges.length;
        max = -Infinity;
        for (var i = 0; i < len; i++) {
            var e = graph.edges[i];
            if (e.layout.weight > max) {
                max = e.layout.weight;
            }
        }
        // 权重归一
        for (var i = 0; i < len; i++) {
            var e = graph.edges[i];
            e.layout.weight /= max;
        }
        this._layout.init(graph, serie.useWorker);
    },
    _buildNodeShapes: function (serie, serieIdx) {
        var graph = this._graph;
        var categories = this.query(serie, 'categories');
        graph.eachNode(function (node) {
            var category = this._getNodeCategory(serie, node.data);
            var queryTarget = [
                node.data,
                category,
                serie
            ];
            var styleQueryTarget = this._getNodeQueryTarget(serie, node.data);
            var emphasisStyleQueryTarget = this._getNodeQueryTarget(serie, node.data, 'emphasis');
            var shape = new IconShape({
                style: {
                    x: 0,
                    y: 0,
                    color: this.deepQuery(styleQueryTarget, 'color'),
                    brushType: 'both',
                    // 兼容原有写法
                    strokeColor: this.deepQuery(styleQueryTarget, 'strokeColor') || this.deepQuery(styleQueryTarget, 'borderColor'),
                    lineWidth: this.deepQuery(styleQueryTarget, 'lineWidth') || this.deepQuery(styleQueryTarget, 'borderWidth')
                },
                highlightStyle: {
                    color: this.deepQuery(emphasisStyleQueryTarget, 'color'),
                    // 兼容原有写法
                    strokeColor: this.deepQuery(emphasisStyleQueryTarget, 'strokeColor') || this.deepQuery(emphasisStyleQueryTarget, 'borderColor'),
                    lineWidth: this.deepQuery(emphasisStyleQueryTarget, 'lineWidth') || this.deepQuery(emphasisStyleQueryTarget, 'borderWidth')
                },
                clickable: serie.clickable,
                zlevel: this.getZlevelBase(),
                z: this.getZBase()
            });
            if (!shape.style.color) {
                shape.style.color = category ? this.getColor(category.name) : this.getColor(node.id);
            }
            shape.style.iconType = this.deepQuery(queryTarget, 'symbol');
            var symbolSize = this.deepQuery(queryTarget, 'symbolSize') || 0;
            if (typeof symbolSize === 'number') {
                symbolSize = [
                    symbolSize,
                    symbolSize
                ];
            }
            // 强制设定节点大小，否则默认映射到 minRadius 到 maxRadius 后的值
            shape.style.width = symbolSize[0] * 2;
            shape.style.height = symbolSize[1] * 2;
            if (shape.style.iconType.match('image')) {
                shape.style.image = shape.style.iconType.replace(new RegExp('^image:\\/\\/'), '');
                shape = new ImageShape({
                    style: shape.style,
                    highlightStyle: shape.highlightStyle,
                    clickable: shape.clickable,
                    zlevel: this.getZlevelBase(),
                    z: this.getZBase()
                });
            }
            // 节点标签样式
            if (this.deepQuery(queryTarget, 'itemStyle.normal.label.show')) {
                shape.style.text = node.data.label == null ? node.id : node.data.label;
                shape.style.textPosition = this.deepQuery(queryTarget, 'itemStyle.normal.label.position');
                shape.style.textColor = this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle.color');
                shape.style.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.normal.label.textStyle') || {});
            }
            if (this.deepQuery(queryTarget, 'itemStyle.emphasis.label.show')) {
                shape.highlightStyle.textPosition = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.position');
                shape.highlightStyle.textColor = this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle.color');
                shape.highlightStyle.textFont = this.getFont(this.deepQuery(queryTarget, 'itemStyle.emphasis.label.textStyle') || {});
            }
            // 拖拽特性
            if (this.deepQuery(queryTarget, 'draggable')) {
                this.setCalculable(shape);
                shape.dragEnableTime = 0;
                shape.draggable = true;
                shape.ondragstart = this.shapeHandler.ondragstart;
                shape.ondragover = null;
            }
            var categoryName = '';
            if (typeof node.category !== 'undefined') {
                var category = categories[node.category];
                categoryName = category && category.name || '';
            }
            // !!Pack data before addShape
            ecData.pack(shape, serie, serieIdx, // data
            node.data, // data index
            node.rawIndex, // name
            node.data.name || '', // category
            // special
            node.category);
            this.shapeList.push(shape);
            this.zr.addShape(shape);
            node.shape = shape;
        }, this);
    },
    _buildLinkShapes: function (serie, serieIdx) {
        var graph = this._graph;
        var len = graph.edges.length;
        for (var i = 0; i < len; i++) {
            var gEdge = graph.edges[i];
            var link = gEdge.data;
            var source = gEdge.node1;
            var target = gEdge.node2;
            var otherEdge = graph.getEdge(target, source);
            var queryTarget = this._getEdgeQueryTarget(serie, link);
            var linkType = this.deepQuery(queryTarget, 'type');
            // TODO 暂时只有线段支持箭头
            if (serie.linkSymbol && serie.linkSymbol !== 'none') {
                linkType = 'line';
            }
            var LinkShapeCtor = linkType === 'line' ? LineShape : BezierCurveShape;
            var linkShape = new LinkShapeCtor({
                style: {
                    xStart: 0,
                    yStart: 0,
                    xEnd: 0,
                    yEnd: 0
                },
                clickable: this.query(serie, 'clickable'),
                highlightStyle: {},
                zlevel: this.getZlevelBase(),
                z: this.getZBase()
            });
            if (otherEdge && otherEdge.shape) {
                // 偏移一定位置放置双向边重叠
                linkShape.style.offset = 4;
                otherEdge.shape.style.offset = 4;
            }
            zrUtil.merge(linkShape.style, this.query(serie, 'itemStyle.normal.linkStyle'), true);
            zrUtil.merge(linkShape.highlightStyle, this.query(serie, 'itemStyle.emphasis.linkStyle'), true);
            if (typeof link.itemStyle !== 'undefined') {
                if (link.itemStyle.normal) {
                    zrUtil.merge(linkShape.style, link.itemStyle.normal, true);
                }
                if (link.itemStyle.emphasis) {
                    zrUtil.merge(linkShape.highlightStyle, link.itemStyle.emphasis, true);
                }
            }
            // 兼容原有写法
            linkShape.style.lineWidth = linkShape.style.lineWidth || linkShape.style.width;
            linkShape.style.strokeColor = linkShape.style.strokeColor || linkShape.style.color;
            linkShape.highlightStyle.lineWidth = linkShape.highlightStyle.lineWidth || linkShape.highlightStyle.width;
            linkShape.highlightStyle.strokeColor = linkShape.highlightStyle.strokeColor || linkShape.highlightStyle.color;
            ecData.pack(linkShape, // serie
            serie, // serie index
            serieIdx, // link data
            gEdge.data, // link data index
            gEdge.rawIndex == null ? i : gEdge.rawIndex, // source name - target name
            gEdge.data.name || source.id + ' - ' + target.id, // link source id
            // special
            source.id, // link target id
            // special2
            target.id);
            this.shapeList.push(linkShape);
            this.zr.addShape(linkShape);
            gEdge.shape = linkShape;
            // Arrow shape
            if (serie.linkSymbol && serie.linkSymbol !== 'none') {
                var symbolShape = new IconShape({
                    style: {
                        x: -5,
                        y: 0,
                        width: serie.linkSymbolSize[0],
                        height: serie.linkSymbolSize[1],
                        iconType: serie.linkSymbol,
                        brushType: 'fill',
                        // Use same style with link shape
                        color: linkShape.style.strokeColor
                    },
                    highlightStyle: { brushType: 'fill' },
                    position: [
                        0,
                        0
                    ],
                    rotation: 0,
                    zlevel: this.getZlevelBase(),
                    z: this.getZBase()
                });
                linkShape._symbolShape = symbolShape;
                this.shapeList.push(symbolShape);
                this.zr.addShape(symbolShape);
            }
        }
    },
    _updateLinkShapes: function () {
        var v = vec2.create();
        var n = vec2.create();
        var p1 = vec2.create();
        var p2 = vec2.create();
        var edges = this._graph.edges;
        for (var i = 0, len = edges.length; i < len; i++) {
            var edge = edges[i];
            var sourceShape = edge.node1.shape;
            var targetShape = edge.node2.shape;
            vec2.copy(p1, sourceShape.position);
            vec2.copy(p2, targetShape.position);
            var edgeShapeStyle = edge.shape.style;
            vec2.sub(v, p1, p2);
            vec2.normalize(v, v);
            if (edgeShapeStyle.offset) {
                n[0] = v[1];
                n[1] = -v[0];
                vec2.scaleAndAdd(p1, p1, n, edgeShapeStyle.offset);
                vec2.scaleAndAdd(p2, p2, n, edgeShapeStyle.offset);
            } else if (edge.shape.type === 'bezier-curve') {
                edgeShapeStyle.cpX1 = (p1[0] + p2[0]) / 2 - (p2[1] - p1[1]) / 4;
                edgeShapeStyle.cpY1 = (p1[1] + p2[1]) / 2 - (p1[0] - p2[0]) / 4;
            }
            edgeShapeStyle.xStart = p1[0];
            edgeShapeStyle.yStart = p1[1];
            edgeShapeStyle.xEnd = p2[0];
            edgeShapeStyle.yEnd = p2[1];
            edge.shape.modSelf();
            if (edge.shape._symbolShape) {
                var symbolShape = edge.shape._symbolShape;
                vec2.copy(symbolShape.position, p2);
                vec2.scaleAndAdd(symbolShape.position, symbolShape.position, v, targetShape.style.width / 2 + 2);
                var angle = Math.atan2(v[1], v[0]);
                symbolShape.rotation = Math.PI / 2 - angle;
                symbolShape.modSelf();
            }
        }
    },
    _syncNodePositions: function () {
        var graph = this._graph;
        for (var i = 0; i < graph.nodes.length; i++) {
            var gNode = graph.nodes[i];
            var position = gNode.layout.position;
            var node = gNode.data;
            var shape = gNode.shape;
            var fixX = shape.fixed || node.fixX;
            var fixY = shape.fixed || node.fixY;
            if (fixX === true) {
                fixX = 1;
            } else if (isNaN(fixX)) {
                fixX = 0;
            }
            if (fixY === true) {
                fixY = 1;
            } else if (isNaN(fixY)) {
                fixY = 0;
            }
            shape.position[0] += (position[0] - shape.position[0]) * (1 - fixX);
            shape.position[1] += (position[1] - shape.position[1]) * (1 - fixY);
            vec2.copy(position, shape.position);
            var nodeName = node.name;
            if (nodeName) {
                var gPos = this.__nodePositionMap[nodeName];
                if (!gPos) {
                    gPos = this.__nodePositionMap[nodeName] = vec2.create();
                }
                vec2.copy(gPos, position);
            }
            shape.modSelf();
        }
    },
    _step: function (e) {
        this._syncNodePositions();
        this._updateLinkShapes();
        this.zr.refreshNextFrame();
        if (this._layout.temperature > 0.01) {
            this._layout.step(this._steps);
        } else {
            this.messageCenter.dispatch(ecConfig.EVENT.FORCE_LAYOUT_END, {}, {}, this.myChart);
        }
    },
    refresh: function (newOption) {
        if (newOption) {
            this.option = newOption;
            this.series = this.option.series;
        }
        this.legend = this.component.legend;
        if (this.legend) {
            this.getColor = function (param) {
                return this.legend.getColor(param);
            };
            this.isSelected = function (param) {
                return this.legend.isSelected(param);
            };
        } else {
            var colorMap = {};
            var count = 0;
            this.getColor = function (key) {
                if (colorMap[key]) {
                    return colorMap[key];
                }
                if (!colorMap[key]) {
                    colorMap[key] = this.zr.getColor(count++);
                }
                return colorMap[key];
            };
            this.isSelected = function () {
                return true;
            };
        }
        this._init();
    },
    dispose: function () {
        this.clear();
        this.shapeList = null;
        this.effectList = null;
        this._layout.dispose();
        this._layout = null;
        this.__nodePositionMap = {};
    },
    getPosition: function () {
        var position = [];
        this._graph.eachNode(function (n) {
            if (n.layout) {
                position.push({
                    name: n.data.name,
                    position: Array.prototype.slice.call(n.layout.position)
                });
            }
        });
        return position;
    }
};
/**
     * 拖拽开始
     */
function ondragstart(param) {
    if (!this.isDragstart || !param.target) {
        // 没有在当前实例上发生拖拽行为则直接返回
        return;
    }
    var shape = param.target;
    shape.fixed = true;
    // 处理完拖拽事件后复位
    this.isDragstart = false;
    this.zr.on(zrConfig.EVENT.MOUSEMOVE, this.onmousemove);
}
function onmousemove() {
    this._layout.temperature = 0.8;
    this._step();
}
/**
     * 数据项被拖拽出去，重载基类方法
     */
function ondragend(param, status) {
    if (!this.isDragend || !param.target) {
        // 没有在当前实例上发生拖拽行为则直接返回
        return;
    }
    var shape = param.target;
    shape.fixed = false;
    // 别status = {}赋值啊！！
    status.dragIn = true;
    //你自己refresh的话把他设为false，设true就会重新调refresh接口
    status.needRefresh = false;
    // 处理完拖拽事件后复位
    this.isDragend = false;
    this.zr.un(zrConfig.EVENT.MOUSEMOVE, this.onmousemove);
}
function _randomInSquare(x, y, size) {
    var v = vec2.create();
    v[0] = (Math.random() - 0.5) * size + x;
    v[1] = (Math.random() - 0.5) * size + y;
    return v;
}
zrUtil.inherits(Force, ChartBase);
// 图表注册
require('../chart').define('force', Force);
module.exports = Force || module.exports;;